{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "nbsphinx": "hidden"
   },
   "source": [
    "This notebook is part of the `clifford` documentation: https://clifford.readthedocs.io/."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#  Space Time Algebra "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  Intro"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook demonstrates how to use `clifford` to work with Space Time Algebra.\n",
    "The Pauli algebra of space  $\\mathbb{P}$, and Dirac algebra of space-time $\\mathbb{D}$, are related using the *spacetime split*.\n",
    "The split is implemented by using a `BladeMap` ([docs](../generated/clifford.BladeMap.html)), which maps a subset of blades in $\\mathbb{D}$ to the blades in $\\mathbb{P}$.\n",
    "This *split* allows a spacetime bivector $F$ to be broken up into relative electric and magnetic fields in space.\n",
    "Lorentz transformations are implemented as rotations in  $\\mathbb{D}$, and the effects on the relative fields are computed with the split. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "First we import `clifford`, instantiate the two algebras, and populate the namespace with the blades of each algebra.\n",
    "The elements of $\\mathbb{D}$ are prefixed with $d$, while the elements of $\\mathbb{P}$ are prefixed with $p$.\n",
    "Although unconventional, it is easier to read and to translate into code. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from clifford import Cl, pretty\n",
    "\n",
    "pretty(precision=1)\n",
    "\n",
    "# Dirac Algebra  `D`\n",
    "D, D_blades = Cl(1,3, firstIdx=0, names='d')\n",
    "\n",
    "# Pauli Algebra  `P`\n",
    "P, P_blades = Cl(3, names='p')\n",
    "\n",
    "# put elements of each in namespace\n",
    "locals().update(D_blades)\n",
    "locals().update(P_blades)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Space Time Split"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To two algebras can be related by the spacetime-split.\n",
    "First, we create a `BladeMap` which relates the bivectors in $\\mathbb{D}$ to the vectors/bivectors in $\\mathbb{P}$.\n",
    "The scalars and pseudo-scalars in each algebra are equated.\n",
    "\n",
    "![](../_static/split.svg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from clifford import BladeMap\n",
    "\n",
    "bm = BladeMap([(d01,p1),\n",
    "               (d02,p2),\n",
    "               (d03,p3),\n",
    "               (d12,p12),\n",
    "               (d23,p23),\n",
    "               (d13,p13),\n",
    "               (d0123, p123)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Splitting a space-time vector (an event)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A vector in $\\mathbb{D}$, represents a unique place in space and time, i.e.  an event.\n",
    "To illustrate the split, create a random event  $X$. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = D.randomV()*10\n",
    "X"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This can be *split* into time and space components by multiplying with the time-vector $d_0$,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X*d0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " and applying the `BladeMap`, which results in a scalar+vector in $\\mathbb{P}$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bm(X*d0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The space and time components can be separated by grade projection, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = bm(X*d0)\n",
    "x(0) # the time component"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x(1) # the space component"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We therefor define a `split()` function, which has a simple condition allowing it to act on a vector or a multivector in $\\mathbb{D}$.\n",
    "Splitting a spacetime bivector will be treated in the next section. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def split(X):\n",
    "    return bm(X.odd*d0+X.even)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "split(X)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The split can be inverted by  applying the `BladeMap` again, and multiplying by $d_0$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = split(X)\n",
    "bm(x)*d0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Splitting a Bivector"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Given a random bivector  $F$ in $\\mathbb{D}$,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "F = D.randomMV()(2)\n",
    "F"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$F$ *splits* into a vector/bivector in $\\mathbb{P}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "split(F)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If $F$ is interpreted as the electromagnetic bivector, the Electric and Magnetic fields can be separated by grade "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "E = split(F)(1)\n",
    "iB = split(F)(2)\n",
    "\n",
    "E"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "iB"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lorentz Transformations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lorentz Transformations are rotations in $\\mathbb{D}$, which are implemented with Rotors.\n",
    "A rotor in G4 will, in general, have scalar, bivector, and quadvector components."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R = D.randomRotor()\n",
    "R"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this way, the effect of a lorentz transformation on the electric and magnetic fields can be  computed by rotating the bivector with  $F \\rightarrow RF\\tilde{R}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "F_ = R*F*~R\n",
    "F_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then splitting into $E$ and $B$ fields"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "E_ = split(F_)(1)\n",
    "E_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "iB_ = split(F_)(2)\n",
    "iB_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lorentz Invariants"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since lorentz rotations in $\\mathbb{D}$, the magnitude of elements of $\\mathbb{D}$ are invariants of the  lorentz transformation.\n",
    "For example, the magnitude of electromagnetic bivector $F$ is invariant, and it can be related to $E$ and $B$ fields in  $\\mathbb{P}$ through the split,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "i = p123 \n",
    "E = split(F)(1)\n",
    "B = -i*split(F)(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "F**2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "split(F**2) == E**2 - B**2 + (2*E|B)*i"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
